/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
#include <stdlib.h>
#include "../inc/bcos_asm.h"
#include "../inc/bcos_pcb.h"
#include "bcos_time.h"

BC_OS_STK   bcos_free_stk[BCOS_FREE_STK_SIZE];
BC_OS_STK   bcos_mainloop_stk[BCOS_MAINLOOP_STK_SIZE];

uint8_t          OSRunning;
bcos_tcb_t       *OSTCBCur, *OSTCBHighRdy;

struct list_head     bcos_tcb_head;
struct list_head	 bcos_waiting_tcb_head;

/* 系统启动后会建立tasklet_handler和mainloop两个任务并初始化 */
bcos_tcb_t			 bcos_free_tcb = BCOS_TCB_STATIC_INIT(bcos_free_tcb, BCOS_FREE_TASK_PRO);
bcos_tcb_t           bcos_mainloop_tcb = BCOS_TCB_STATIC_INIT(bcos_mainloop_tcb, BCOS_MAINLOOP_TASK_PRO);

/* 定义一个tasklet的链表头 */
struct list_head      bcos_tasklet_h = LIST_HEAD_INIT(bcos_tasklet_h);

/* 空闲任务处理tasklet */
static void bcos_free_handler(void *p_arg)
{
	bcos_tasklet_t *first;
#if BCOS_LOWER_MODE_SUPPORT
	bcos_tcb_t *tcb;
	BC_OS_TICK sleep_ticks = 0;
#endif
	
	while(1)
	{
		/* 判断是否有tasklet任务需要处理 */
		if (!list_empty(&bcos_tasklet_h))
		{
			first = list_first_entry(&bcos_tasklet_h, bcos_tasklet_t, list);
			if (first->stamp <= bcos_ticks)
			{
				/* 
				 * 将tasklet从队列中删除，这个操作必须放在执行tasklet任务处理函数之前。 
				 * 因为，如果这是一个重复的tasklet，用户有可能在任务处理函数中将同一个
				 * tasklet添加到队列中，在执行完处理函数删除时就会将新添加的任务删除掉
				 */
				list_del_init(&first->list);
				/* 执行tasklet处理任务 */
				first->handler(first->ptr);
			}
		}
#if BCOS_LOWER_MODE_SUPPORT
		/* 如果系统配置支持低功耗模式则调用用户实现的低功耗接口 */
		tcb = list_first_entry(&bcos_waiting_tcb_head, bcos_tcb_t, list);
		
		/* 计算系统需要休眠的tick数 */
		sleep_ticks = BCOS_MINI((tcb->delay_stamp - bcos_ticks), (first->stamp - bcos_ticks));
		/* 判断是否满足最低休眠时间 */
		if(sleep_ticks >= BCOS_MINI_SLEEP_TICKS)
		{
			/* 该接口为休眠和唤醒的接口, 用户需要实现该接口。该接口提供了需要休眠的时间和
			   系统滴答计数器的执行,用户需要休眠相应的时间后计算并恢复系统滴答计数器的值*/
			bcos_lowpower_enter_and_ticks_recovery(sleep_ticks, &bcos_ticks);
		}
		else
		{
			/* 不满足最低休眠时间，CPU进入睡眠模式 */
			__asm volatile ("wfi");
		}
#endif
	}
}

/*
 * 初始化栈， 将任务回调函数和参数赋值到对应位置
 *
 * @return: psp
 */
BC_OS_STK *bcos_init_stack(void (*task)(void *p_arg), void *p_arg, BC_OS_STK *ptos)
{
    BC_OS_STK *stk;

    stk       = ptos;                              /* Load stack pointer                                 */
                                                   /* Registers stacked as if auto-saved on exception    */
    *(stk)    = (uint32_t)0x01000000L;             /* xPSR                                               */
    *(--stk)  = (uint32_t)task;                    /* Entry Point                                        */
    *(--stk)  = (uint32_t)0xFFFFFFFEL;             /* R14 (LR) (init value will cause fault if ever used)*/
    *(--stk)  = (uint32_t)0x12121212L;             /* R12                                                */
    *(--stk)  = (uint32_t)0x03030303L;             /* R3                                                 */
    *(--stk)  = (uint32_t)0x02020202L;             /* R2                                                 */
    *(--stk)  = (uint32_t)0x01010101L;             /* R1                                                 */
    *(--stk)  = (uint32_t)p_arg;                   /* R0 : argument                                      */

                                                   /* Remaining registers saved on process stack         */
    *(--stk)  = (uint32_t)0x11111111L;             /* R11                                                */
    *(--stk)  = (uint32_t)0x10101010L;             /* R10                                                */
    *(--stk)  = (uint32_t)0x09090909L;             /* R9                                                 */
    *(--stk)  = (uint32_t)0x08080808L;             /* R8                                                 */
    *(--stk)  = (uint32_t)0x07070707L;             /* R7                                                 */
    *(--stk)  = (uint32_t)0x06060606L;             /* R6                                                 */
    *(--stk)  = (uint32_t)0x05050505L;             /* R5                                                 */
    *(--stk)  = (uint32_t)0x04040404L;             /* R4                                                 */

    return (stk);
}

/*
 * 创建任务，需要静态定义任务控制块和栈空间
 * 任务优先级可以是0x00 - 0xFD
 *
 * @param:
 * 		tcb: 	任务控制块指针
 *		task：	任务处理函数
 * 		p_arg: 	任务函数参数
 *		ptos:	栈底指针
 */
void bcos_task_create(bcos_tcb_t *tcb, void (*task)(void *ptr), void *p_arg, BC_OS_STK *ptos)
{
    BC_OS_STK *psp;
	bcos_tcb_t *pos, *n;

    /* 初始化堆栈 */
    psp = bcos_init_stack(task, p_arg, ptos);
    tcb->OSTCBStkPtr = psp;
	tcb->OSTCBStkTopPtr = NULL;
    
	/* 将任务添加到就绪任务队列中 */
	list_ascending_order_add(tcb, pos, n, &bcos_tcb_head, list, priority);
}

/*
 * 创建任务，任务控制块和栈空间用动态分配的方式
 *
 * @param:
 *		task: 任务处理函数指针
 * 		p_arg: 任务处理函数参数
 * 		prio： 任务优先级
 * 		task_size: 任务栈的深度
 *
 * @return
 *		返回任务控制块指针，如果指针不为NULL则任务创建成功，否在任务创建失败
 */
bcos_tcb_t *bcos_task_malloc(void (*task)(void *ptr), void *p_arg, uint8_t prio, uint16_t stack_size)
{
	bcos_tcb_t *pos, *n, *tcbp = NULL;
	
	/* 分配任务控制块的内存空间 */
	tcbp = (bcos_tcb_t *)bcos_malloc(sizeof(bcos_tcb_t));
	if(tcbp)
	{
		/* 分配栈的内存空间*/
		tcbp->OSTCBStkTopPtr = (BC_OS_STK *)bcos_malloc(stack_size * sizeof(BC_OS_STK));
		if(tcbp->OSTCBStkTopPtr)
		{
			/* 对栈进行初始化 */
			tcbp->OSTCBStkPtr = bcos_init_stack(task, p_arg, (tcbp->OSTCBStkTopPtr + stack_size - 1));
			tcbp->priority = prio;
			/* 将任务添加到就绪任务链表 */
			list_ascending_order_add(tcbp, pos, n, &bcos_tcb_head, list, priority);
		}
		else
		{
			bcos_free(tcbp);
		}
	}
	
	return tcbp;
}

/* 销毁任务，如果任务的任务控制块和栈空间是动态分配的则将这些内存空间释放 */
void bcos_task_destroy(bcos_tcb_t *tcb)
{
	uint32_t cpu_sr;
	
	/* 任务销毁过程中系统不能进行调度，这里关闭系统调度和屏蔽中断 */
	OS_ENTER_CRITICAL();

	/*参数有效性检查*/
	if(tcb)
	{
		/* 判断任务是否在队列中 */
		if(!list_empty(&tcb->list))
		{
			/* 将任务控制块从队列中移除 */
			list_del_init(&tcb->list);
			
			/* 如果当前运行的任务就是要销毁的任务则调度到新的任务后将当前任务销毁 */
			if(OSTCBCur == tcb)
			{
				OSTCBHighRdy = list_first_entry(&bcos_tcb_head, bcos_tcb_t, list);
				OSCtxSw();
			}
		
			/* 判断任务控制块和栈是不是动态分配的，如果是需要释放掉 */
			if(tcb->OSTCBStkTopPtr)
			{
				bcos_free(tcb->OSTCBStkTopPtr);
				bcos_free(tcb);
			}
		}
	}
	OS_EXIT_CRITICAL();
}

/*
 * 将tasklet节点添加到tasklet执行队列， 如果时立即执行的tasklet，系统会
 * 尽快调度执行，如果是延时任务，系统会在超时时触发。
 * 
 * @prarm: 
 *          tasklet: tasklet节点的指针；
 *          ms:      多少毫秒后执行处理函数；
 * 
 * @return: none;
 */
void bcos_tasklet_post(bcos_tasklet_t *tasklet, BC_OS_TICK ms)
{
    uint32_t cpu_sr;
    bcos_tasklet_t *pos, *n;

    OS_ENTER_CRITICAL();
	
	/* 防止重复添加 */
	if(!list_empty(&tasklet->list))
		list_del_init(&tasklet->list);

	/* 计算触发该tasklet的时间戳 */
	tasklet->stamp = bcos_ticks + ms;
	
	/* 将tasklet添加到队列中 */
	list_ascending_order_add(tasklet, pos, n, &bcos_tasklet_h, list, stamp);
    
    OS_EXIT_CRITICAL();
}

/* 取消tasklet任务 */
void bcos_tasklet_cancel(bcos_tasklet_t *tasklet)
{
	uint32_t cpu_sr;
	
	/* 必须保证原子的将tasklet从队列中删除 */
	OS_ENTER_CRITICAL();
	if(!list_empty(&tasklet->list))
	{
		list_del_init(&tasklet->list);
	}
	OS_EXIT_CRITICAL();
}

/*
 * 系统启动， 初始化tasklet处理任务和主循环任务的堆栈
 * 对PSP进行初始化并调度到主循环执行
 */
static void bcos_start(void)
{
    BC_OS_STK *psp;
	bcos_tcb_t *tcb, *pos, *n;
	
	/* 初始化就绪任务链表头和等待任务链表头 */
	INIT_LIST_HEAD(&bcos_tcb_head);
	INIT_LIST_HEAD(&bcos_waiting_tcb_head);
	
	/* 对空闲任务栈进行初始化 */
	psp = bcos_init_stack(bcos_free_handler, NULL, \
                        &bcos_free_stk[BCOS_FREE_STK_SIZE - 1]);
    bcos_free_tcb.OSTCBStkPtr = psp;
	tcb = &bcos_free_tcb;
	/* 将空闲任务添加到就绪链表中 */
	list_ascending_order_add(tcb, pos, n, &bcos_tcb_head, list, priority);

    psp = bcos_init_stack(mainloop, NULL, \
                        &bcos_mainloop_stk[BCOS_MAINLOOP_STK_SIZE - 1]);
    bcos_mainloop_tcb.OSTCBStkPtr = psp;
	tcb = &bcos_mainloop_tcb;
	list_ascending_order_add(tcb, pos, n, &bcos_tcb_head, list, priority);

    OSTCBHighRdy = &bcos_mainloop_tcb;
    OSRunning = 1;

	/* 启动系统调度 */
    OSStartHighRdy();
}

/*
 * 系统调度
 */
void bcos_scheduing(void)
{
    uint32_t cpu_sr;
    bcos_tcb_t *first, *pos, *n;

	/* 屏蔽中断 */
    OS_ENTER_CRITICAL();
	
	/* 任务等待队列不为空 */
	if (!list_empty(&bcos_waiting_tcb_head))
	{
		/* 从任务等待队列中检查是否有超时任务 */
		first = list_first_entry(&bcos_waiting_tcb_head, bcos_tcb_t, list);
		if (first->delay_stamp <= bcos_ticks)
		{
			/* 任务等待超时，从等待队列中删除任务并添加到就绪队列中 */
			list_del_init(&first->list);
			list_ascending_order_add(first, pos, n, &bcos_tcb_head, list, priority);
		}
	}
	
	first = list_first_entry(&bcos_tcb_head, bcos_tcb_t, list);
	/* 比较任务优先级，判断是否可以抢占 */
	if(first->priority < OSTCBCur->priority)
	{
		OSTCBHighRdy = first;
		OSCtxSw();
	}
	
    OS_EXIT_CRITICAL();
}

int main(void)
{
#if defined(BCOS_MEM_MANGER) && (BCOS_MEM_MANGER != BCOS_MEM_MALLOC)
	bcos_mem_init();
#endif
	/* 系统启动 */
    bcos_start();

    while (1);
}

void HardFault_Handler(void)
{
	while(1)
	{}
}

